// ----------------------------------------------------------------------------
// commandline.h
// ----------------------------------------------------------------------------
/*
 Description:
 コマンドライン引数を読み取る為のユーティリティ.
 ----------------------------------------------------------------
 使い方.
 
 1. アプリケーションから取得できるコマンドライン引数をCommandLineクラスの
    インスタンスクラスに渡す.
 
	CommandLine cmd(argc, argv);
 
 2. 任意の引数が存在するか確認したい場合、HasArg メソッド、引数のパラメータ
    文字列を取得したい場合は FindOption メソッドを利用する.
 
    if(cmd.HasArg("Quit")) printf("'quit' command found.");
    const char* ip = cmd.FindOption("ipaddress");
 
 3. 複数の引数を取得したい場合は、FindOption メソッドの第三引数を指定する.
 
    const char* multiArg = cmd.FindOption("MultiArg", "default", n); // 第n引数を取得. 
 
 4. フラグをbool型、int型、float型として取得したい場合は、
	GetFlag, GetInt, GetFloat の各メソッドを利用する. 
 
	bool flag = cmd.GetFlag ("DebugMode");
    int  valI = cmd.GetInt  ("IntValue");
	int  valF = cmd.GetFloat("FloatValue");
 
 */
#pragma once
#include <stdlib.h>
#include <fw/base/core/macros.h>
#include <fw/base/core/assertion.h>
#include <fw/base/runtime/string_proxy.h>

namespace fw
{
	class CommandLine
	{
	private:
		int					m_argc;
		char const* const*	m_argv;
		
		const char* Find(const char* shortName, const char* longName, int argIndex) const
		{
			for(int ai=0; ai<m_argc; ++ai)
			{
				const char* arg = m_argv[ai];
				if(*arg=='-' || *arg=='/')
				{
					++arg;
					bool flag = false;
					// longName は shortName よりも優先する.
					if(longName)
					{
						if(!FW_STRICMP(longName, arg))
						{
							flag = true;
						}
					}
					else if(shortName)
					{
						if(!FW_STRICMP(shortName, arg))
						{
							flag = true;
						}
					}
					if(flag)
					{
						if(argIndex==0)
						{
							return "";
						}
						else if((argIndex+ai)<m_argc)
						{
							int aai;
							for(aai=ai+1; aai<(argIndex+ai); ++aai)
							{
								if(*m_argv[aai]=='-' || *m_argv[aai]=='/')
								{
									return nullptr; // 次のフラグを発見した場合、指定したパラメータの範囲は無効である.
								}
							}
							return (*m_argv[aai]=='-' || *m_argv[aai]=='/') ? nullptr : m_argv[aai];
						}
					}
				}
			}
			return nullptr;
		}
		
	public:
		CommandLine(int argc, char const* const* argv)
		: m_argc(argc)
		, m_argv(argv)
		{
		}
		
		const char*		FindOption(const char* Name, const char* defaultArg=nullptr, int index=1) const
		{
			FW_ASSERT(index>=0, "Wrong parameter range.[%d]", index);
			const char* result = Find(nullptr, Name, 1);
			return (result == nullptr) ? defaultArg : result;
		}

		bool			HasArg(const char* Name) const
		{
			return (FindOption(Name, nullptr, 0) == nullptr) ? false : true;
		}
	
		bool			GetFlag(const char* Name, bool defaultFlag=false) const
		{
			const char* result = FindOption(Name, nullptr, 1);
			if(result!=nullptr)
			{
				if(*result== '0' || !FW_STRICMP(result, "false") || !FW_STRICMP(result, "on"))
				{
					return false;
				}
				if(*result== '1' || !FW_STRICMP(result, "true")  || !FW_STRICMP(result, "off"))
				{
					return true;
				}
			}
			return defaultFlag;
		}
		
		int				GetInt(const char* Name, int defaultValue=0) const
		{
			const char* result = FindOption(Name, nullptr, 1);
			if(result!=nullptr)
			{
				return atoi(result);
			}
			return defaultValue;
		}

		float			GetFloat(const char* Name, float defaultValue=0.0f) const
		{
			const char* result = FindOption(Name, nullptr, 1);
			if(result!=nullptr)
			{
				return atof(result);
			}
			return defaultValue;
		}
		
	}; // class CommandLine
	
} // namespace fw

